/*
 * List.java
 * Created on May 2, 2008, 11:01 PM
 */

package view;

import base.ResourceAccess;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import utils.Util;

/**
 *
 * @author Erol Hira
 */
public class List extends Component{
    
    private byte type;
    public static final byte IMPLICIT = 0;
    public static final byte MULTIPLE = 1;
    public static final byte EXCLUSIVE = 2;
    
    /**
     *  [x][y] --> x:element index  y:line index 
     */
    private String[][] data;
    private int selectedElementInPage; // from 0 to n
    private int startingElementIndex;  // x of the starting element in the data
    
    private boolean[] choices; // true : selected
    private int chosenRadioIndex;
    
    protected boolean fullScreen;
    
    private boolean frameLineVisible;
    private byte frameLineTickness = 1;
    private Color frameLineColor = Color.BLUE;
    
    private Image elemBgImage;
    private Image elemSelectedImg;
    private Color selectedBgColor = Color.YELLOW;
    private byte lineCountOfAnElement;
    private byte marginSelectedElement_vertical = 2;
    private byte marginSelectedElement_horizontal = 2;
    
    private byte spaceBetweenElements = 2;
    
    
    private Image lineIcon;
    private Image selectedLineIcon;
    private byte lineHeight;
    private byte minDistBetweenIconAndText = 4;
    private byte lineIconWidth = 8; // get from lineIcon in the setupList()
    
    private Color softLineColor;
    private Color hardLineColor;    
    
    //
    private byte countOfElementsInCurPage;
    private byte maxCountOfElementsInCurPage;
        
    //
    private short oll = 12;
    private short olt = 2;
    private Color olc = Color.BLUE;
    private short ill = 4;
    private Color ilc = Color.BLACK;    
    private boolean outerLineExists = false;
    private short ot = 1;
    private Color oc = Color.RED;    
    
    private Functor[] commands;
    private Functor defaultCommand;        
    
    public List(String[][] data, int y, int width, int maxCountOfElementsInCurPage, byte lineHeight){        
        this(data, null, null, false, null, null, null, lineHeight, Color.WHITE,
                    y, width, maxCountOfElementsInCurPage);
    }
    
    /**
     *  height is ignored if fullScreen == true 
     */
    public List(String[][] data, Functor[] commands, Functor defaultCommand, boolean fullScreen, 
                Image elemBgImage, Image elemSelectedImg,
                Image lineIcon, byte lineHeight,Color bgColor,
                int y, int width, int maxCountOfElementsInCurPage) {
        
        super(width, 0);
        this.data = data;
        this.commands = commands;
        this.defaultCommand = defaultCommand;
        this.fullScreen = fullScreen;
        this.elemBgImage = elemBgImage;
        this.elemSelectedImg = elemSelectedImg;
        this.lineIcon = lineIcon;
        this.lineHeight = lineHeight;
        this.bgColor = bgColor;
        this.y = y;
        this.choices = new boolean[data.length];  
        this.maxCountOfElementsInCurPage = (byte)maxCountOfElementsInCurPage;
        
        lineCountOfAnElement = (byte) data[0].length;
        
        height = maxCountOfElementsInCurPage * lineCountOfAnElement * lineHeight;
    }

    protected void init() {
        focusable = true;
        softLineColor = getFgColor();                
        hardLineColor = getFgColor();
    }   
    
    /**
     *   must be called after the list component added to the container.
     */
    public void setupList() {
        
        if(fullScreen){
            x = 0;
            y = 0;
            width = container.getWidth();
            height = container.getCanvasContentHeight();
        } else {
            x = (container.getWidth() - width) / 2;
            y = (container.getHeight() - height) / 2;
        }          
                
        calculateCountOfElementsInCurPage();
        lineIconWidth = lineIcon != null ? (byte) lineIcon.getWidth() : lineIconWidth;
    }
    
    public void paintComponent(Graphics g){
        
        if(readyToPaint() == false){
            return;
        }
        
        initPaint();
        
        paintBorder(g);
        //paintBG(g);
        paint(g);        
        
        setPaintFlag(false);
    }
    
    public void paint(Graphics g) {                
        
        paintList(g);
    }        
    
    private void paintList(Graphics g) {                
        
        GuiUtils.setColor(g, bgColor);
        g.fillRect(get_x_content(), get_y_content(), width, height);        
        
        int y_content = get_y_content();
        for(int i = 0; i < data.length && i < maxCountOfElementsInCurPage; i++){
            int dataIndex = startingElementIndex + i;
            String[] elemData = dataIndex >= data.length ? null : data[dataIndex];
            paintElement(g, elemData, y_content, i);
            y_content += lineCountOfAnElement * lineHeight;
        }
        
        if(frameLineVisible){
            GuiUtils.drawRectangle(g, get_x_content(), get_y_content(), width, height, frameLineColor, frameLineColor, frameLineTickness);
            //g.drawRect(get_x_content(), get_y_content(), width, height);
        }
    }

    public void paintElement(Graphics g, String[] elemData, int y_content, int indexInPage){                        
        
        if(indexInPage == selectedElementInPage){
            
            GuiUtils.setColor(g, selectedBgColor);
            g.fillRect(get_x_content() + marginSelectedElement_horizontal, 
                    y_content + marginSelectedElement_vertical, 
                    width - 2*marginSelectedElement_horizontal, 
                    lineHeight * lineCountOfAnElement - 2*marginSelectedElement_vertical);
        }
        
        /*
        GuiUtils.setColor(g, fgColor);
        GuiUtils.drawRectangle(g, get_x_content(), y_content - rectangleTickness, 
                                width, lineHeight * lineCountOfAnElement + rectangleTickness, 
                                hardLineColor, hardLineColor, rectangleTickness);
        */
        
        if(indexInPage < countOfElementsInCurPage){
            
            int y_cur = y_content;
        
            paintElementSelection(g, indexInPage, y_cur);

            for(int i = 0; i < lineCountOfAnElement; i++){                                                                        

                font.write(g, elemData[i], 
                        get_x_content() + marginLeft + lineIconWidth + minDistBetweenIconAndText, 
                        y_cur, 
                        width - marginLeft, 
                        lineHeight - marginTop, 
                        alignment);

                y_cur += lineHeight;
            }
        }
    }
        
    private void paintElementSelection(Graphics g, int indexInPage, int y_cur){
        
        if(IMPLICIT == type){ // check
                        
            int x = get_x_content() + marginLeft + ill/2;
            int y = y_cur + (lineHeight * lineCountOfAnElement)/2;
            
            GuiUtils.fillCircleFromCenter(g, x, y, ill, ilc);            
            
        } else if(EXCLUSIVE == type){ // radio
            
            int x = get_x_content() + marginLeft + oll;
            int y = y_cur + (lineHeight * lineCountOfAnElement)/2;                        
            
            GuiUtils.drawRadioButton(g, x, y, oll, olt, olc, ill, ilc, 
                                    chosenRadioIndex == getIndex(indexInPage), 
                                    outerLineExists, ot, oc, bgColor);
            
        } else if(MULTIPLE == type){ // check
            
            int x = get_x_content() + marginLeft;
            int y = y_cur + (lineHeight * lineCountOfAnElement)/2 - oll/2;
            
            GuiUtils.drawCheckboxButton(g, x, y, oll, olt, olc, ill, ilc, 
                                    isChosen(getIndex(indexInPage)), 
                                    outerLineExists, ot, oc, bgColor);
        }
        
        /*
        if(lineIcon != null){
            Image icon = indexInPage == selectedElementInPage ? selectedLineIcon : lineIcon;
            g.drawImage(icon, 
                get_x_content() + marginLeft, 
                y_cur + lineHeight, 
                Graphics.LEFT | Graphics.VCENTER);
        } else {
            String elementCh = indexInPage == selectedElementInPage ? "a" : "o";
            font.write(g, elementCh, 
                        get_x_content() + marginLeft, 
                        y_cur + lineHeight/2, 
                        width - marginLeft, 
                        lineHeight - marginTop,
                        alignment);
        }
        */
    }        
    
    public void calculateCountOfElementsInCurPage(){
        countOfElementsInCurPage = 0;        
        countOfElementsInCurPage = (byte)(data.length - startingElementIndex);
        countOfElementsInCurPage = (byte)(countOfElementsInCurPage > maxCountOfElementsInCurPage ? maxCountOfElementsInCurPage : countOfElementsInCurPage);
    }    
    
    
    //---------------------------------------------------------------------
    
    protected void doUP() {
        selectedElementInPage --;
        if(selectedElementInPage < 0){
            
            if(startingElementIndex - maxCountOfElementsInCurPage < 0){
                                
                if(startingElementIndex == 0 && data.length == maxCountOfElementsInCurPage){
                    
                    selectedElementInPage = data.length - 1;                    
                    
                } else if(startingElementIndex == 0 && data.length % maxCountOfElementsInCurPage == 0){
                
                    startingElementIndex = data.length - maxCountOfElementsInCurPage;
                    selectedElementInPage = 0;
                    
                } else {
                    
                    startingElementIndex = data.length - data.length % maxCountOfElementsInCurPage;                
                    selectedElementInPage = 0;
                }
                
            } else {
                
                startingElementIndex -= maxCountOfElementsInCurPage;
                selectedElementInPage = 0;
            }
        }
        
        calculateCountOfElementsInCurPage();
        
        System.out.println("selectedElementInPage:" + selectedElementInPage + " startingElementIndex:" + startingElementIndex + " countOfElementsInCurPage:" + countOfElementsInCurPage);
        
        repaint();
    }

    protected void doDOWN() {
        selectedElementInPage ++;
        if(selectedElementInPage + 1 > countOfElementsInCurPage){
            
            if(startingElementIndex + countOfElementsInCurPage == data.length){
                
                startingElementIndex = 0;
                selectedElementInPage = 0;
                
            } else {
                
                startingElementIndex += countOfElementsInCurPage;
                selectedElementInPage = 0;
            }
        }
        
        calculateCountOfElementsInCurPage();
        
        System.out.println("selectedElementInPage:" + selectedElementInPage + " startingElementIndex:" + startingElementIndex + " countOfElementsInCurPage:" + countOfElementsInCurPage);
        
        repaint();
    }

    protected void doFire() {
        
        if(MULTIPLE == type){
            
            choices[getSelectedIndex()] = !choices[getSelectedIndex()];
            
            repaint();
            
        } else if(EXCLUSIVE == type) {
            
            chosenRadioIndex = getSelectedIndex();
            
            repaint();
            
        } else if(IMPLICIT == type) {
            
            if(commands != null){
            
                commands[getSelectedIndex()].doFunc();

            } else {

                defaultCommand.doFunc();
            }
        }                
    }        

    public void onFocus() {
        border.focus();
    }

    public void onFocusLost() {
        border.focusLost();
    }        
    
    //---------------------------------------------------------------------    
    
    public int getSelectedIndex(){
        return startingElementIndex + selectedElementInPage;
    }                
    
    private int getIndex(int indexInPage){
        return startingElementIndex + indexInPage;
    }
    
    private boolean isChosen(int index){
        return choices[index];
    }
    
    public void resetChoices(){
        for(int i = 0; i < choices.length; i++){
            choices[i] = false;
        }
    }
    
    //---------------------------------------------------------------------
    
    public String[][] getData() {
        return data;
    }

    public void setData(String[][] data) {
        this.data = data;
    }

    public boolean isFullScreen() {
        return fullScreen;
    }

    public void setFullScreen(boolean fullScreen) {
        this.fullScreen = fullScreen;
    }

    public byte getMinDistBetweenIconAndText() {
        return minDistBetweenIconAndText;
    }

    public void setMinDistBetweenIconAndText(byte minDistBetweenIconAndText) {
        this.minDistBetweenIconAndText = minDistBetweenIconAndText;
    }

    public byte getLineIconWidth() {
        return lineIconWidth;
    }

    public void setLineIconWidth(byte lineIconWidth) {
        this.lineIconWidth = lineIconWidth;
    }

    public Color getSelectedBgColor() {
        return selectedBgColor;
    }

    public void setSelectedBgColor(Color selectedBgColor) {
        this.selectedBgColor = selectedBgColor;
    }

    public Image getLineIcon() {
        return lineIcon;
    }

    public void setLineIcon(Image lineIcon) {
        this.lineIcon = lineIcon;
    }

    public Image getSelectedLineIcon() {
        return selectedLineIcon;
    }

    public void setSelectedLineIcon(Image selectedLineIcon) {
        this.selectedLineIcon = selectedLineIcon;
    }

    public void setCommands(Functor[] commands) {
        this.commands = commands;
    }

    public void setDefaultCommand(Functor defaultCommand) {
        this.defaultCommand = defaultCommand;
    }

    public byte getType() {
        return type;
    }

    public void setType(byte type) {
        this.type = type;
    }

    public short getOll() {
        return oll;
    }

    public void setOll(short oll) {
        this.oll = oll;
    }

    public short getOlt() {
        return olt;
    }

    public void setOlt(short olt) {
        this.olt = olt;
    }

    public Color getOlc() {
        return olc;
    }

    public void setOlc(Color olc) {
        this.olc = olc;
    }

    public short getIll() {
        return ill;
    }

    public void setIll(short ill) {
        this.ill = ill;
    }

    public Color getIlc() {
        return ilc;
    }

    public void setIlc(Color ilc) {
        this.ilc = ilc;
    }

    public boolean isOuterLineExists() {
        return outerLineExists;
    }

    public void setOuterLineExists(boolean outerLineExists) {
        this.outerLineExists = outerLineExists;
    }

    public short getOt() {
        return ot;
    }

    public void setOt(short ot) {
        this.ot = ot;
    }

    public Color getOc() {
        return oc;
    }

    public void setOc(Color oc) {
        this.oc = oc;
    }

    public boolean isFrameLineVisible() {
        return frameLineVisible;
    }

    public void setFrameLineVisible(boolean frameLineVisible) {
        this.frameLineVisible = frameLineVisible;
    }

    public byte getMarginSelectedElement_vertical() {
        return marginSelectedElement_vertical;
    }

    public void setMarginSelectedElement_vertical(byte marginSelectedElement_vertical) {
        this.marginSelectedElement_vertical = marginSelectedElement_vertical;
    }

    public byte getMarginSelectedElement_horizontal() {
        return marginSelectedElement_horizontal;
    }

    public void setMarginSelectedElement_horizontal(byte marginSelectedElement_horizontal) {
        this.marginSelectedElement_horizontal = marginSelectedElement_horizontal;
    }

    public byte getFrameLineTickness() {
        return frameLineTickness;
    }

    public void setFrameLineTickness(byte frameLineTickness) {
        this.frameLineTickness = frameLineTickness;
    }

    public Color getFrameLineColor() {
        return frameLineColor;
    }

    public void setFrameLineColor(Color frameLineColor) {
        this.frameLineColor = frameLineColor;
    }

    protected void setHighLevelProperty(int property, String value) {
        
        if(Fields.TYPE == property){
            
            type = Byte.parseByte(value);
            
        } else if(Fields.DATA == property){
            
            
            
        } else if(Fields.FULLSCREEN == property){
            
            fullScreen = Util.booleanValue(value);
            
        } else if(Fields.FRAME_LINE_VISIBLE == property){
        
            frameLineVisible = Util.booleanValue(value);
            
        } else if(Fields.FRAME_LINE_TICKNESS == property){
        
            frameLineTickness = Byte.parseByte(value);
            
        } else if(Fields.FRAME_LINE_COLOR == property){
            
            frameLineColor = GuiUtils.getColor(value);
            
        } else if(Fields.ELEMENT_BG_IMAGE == property){
            
            elemBgImage = ResourceAccess.getImage(Integer.parseInt(value));
            
        } else if(Fields.ELEMENT_SELECTED_IMAGE == property){
            
            elemSelectedImg = ResourceAccess.getImage(Integer.parseInt(value));
            
        } else if(Fields.SELECTED_BG_COLOR == property){
            
            selectedBgColor = GuiUtils.getColor(value);
            
        } else if(Fields.MARGIN_SELECTED_ELEMENT_VERTICAL == property){
            
            marginSelectedElement_vertical = Byte.parseByte(value);
            
        } else if(Fields.MARGIN_SELECTED_ELEMENT_HORIZONTAL == property){
            
            marginSelectedElement_horizontal = Byte.parseByte(value);
            
        } else if(Fields.SPACE_BETWEEN_ELEMENTS == property){
            
            spaceBetweenElements = Byte.parseByte(value);
            
        } else if(Fields.LINE_ICON == property){
        
            lineIcon = ResourceAccess.getImage(Integer.parseInt(value));
            
        } else if(Fields.SELECTED_LINE_ICON == property){
        
            selectedLineIcon = ResourceAccess.getImage(Integer.parseInt(value));
            
        } else if(Fields.LINE_HEIGHT == property){
            
            lineHeight = Byte.parseByte(value);
            
        } else if(Fields.MIN_DIST_BETWEEN_ICON_AND_TEXT == property){
            
            minDistBetweenIconAndText = Byte.parseByte(value);
            
        } else if(Fields.MAX_COUNT_OF_ELEMENTS_IN_CURRENT_PAGE == property){
            
            maxCountOfElementsInCurPage = Byte.parseByte(value);
            
        } else if(Fields.OLL == property){
            
            oll = Short.parseShort(value);
            
        } else if(Fields.OLT == property){
            
            olt = Short.parseShort(value);
            
        } else if(Fields.OLC == property){
            
            olc = GuiUtils.getColor(value);
            
        } else if(Fields.ILL == property){
            
            ill = Short.parseShort(value);
            
        } else if(Fields.ILC == property){
            
            ilc = GuiUtils.getColor(value);
            
        } else if(Fields.OUTER_LINE_EXISTS == property){
            
            outerLineExists = Util.booleanValue(value);
            
        } else if(Fields.OT == property){
            
            ot = Short.parseShort(value);
            
        } else if(Fields.OC == property){
            
            oc = GuiUtils.getColor(value);
            
        } else if(Fields.DEFAULT_COMMAND == property){
            
            
            
        }  else if(Fields.COMMANDS == property){
            
            
            
        }
    }            
    
}                
